package com.ebt.m.customer.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import android.content.ContentValues;
import android.database.SQLException;
import android.util.Log;

import com.ebt.m.utils.DataAnnotationCompareExcept;
/**
 * a util class used to compare two object
 * 
 * @author rick.wang
 * 
 */
public class CompareObjectUtils {
	
	public static final String TAG="compare";
	public static HashSet<Class> basicClasses = new HashSet<Class>();
	
	/**
     * 对比两个object是否相等
     *    如果有一个是null，返回false
     *    如果两者所属的类不同，返回false
     *    如果两者的类型属于基本类型或者基本类型的包装类，则直接比较
     *    如果两者不属于基本类型或者基本类型的包装类，则根据其所有的getDeclaredFields()（即，
     *       获得某个类的所有申明的字段，即包括public、private和proteced，但是不包括父类
     *       的申明字段）。比对这些字段是否相等，如果全部一一相等，则返回true，否则返回false。
     *       当其中的某个field具有DataAnnotationCompareExcept的annotation标志，则
     *       跳过不比较。
     *       
     *
     * @param o1 对比的object的第一个
     * 
     * @param o2 对比的object的第二个
     * 
     * @return 返回两个对象是否相等
     */
	public static boolean compareObject(Object o1, Object o2){
		
		if(o1 == null || o2 == null){
			if(o1==null){
				Log.d(TAG, "compareObject o1 == null return false");
			}
			if(o2==null){
				Log.d(TAG, "compareObject o2 == null return false");
			}
			
			return false;
		}
		if(o1.getClass().getName() != o2.getClass().getName()){
			Log.d(TAG, "compareObject o1 class != o2 class return false");
			return false;
		}
		
		try {
			Class<?> clazz = o1.getClass();
			Log.d(TAG, "compareObject class is " + clazz.getName());
			if(basicClasses.size() == 0){
				
				basicClasses.add(Integer.class);
				basicClasses.add(int.class);
				basicClasses.add(Float.class);
				basicClasses.add(float.class);
				basicClasses.add(Double.class);
				basicClasses.add(double.class);
				basicClasses.add(Long.class);
				basicClasses.add(long.class);
				basicClasses.add(Byte.class);
				basicClasses.add(byte.class);
				basicClasses.add(Boolean.class);
				basicClasses.add(boolean.class);
				basicClasses.add(Short.class);
				basicClasses.add(short.class);
				basicClasses.add(Character.class);
				basicClasses.add(char.class);
				
				basicClasses.add(String.class);
				basicClasses.add(Date.class);
			}

			if(basicClasses.contains(clazz)){
				return o1.equals(o2);
			}
			
			Field[] fs = clazz.getDeclaredFields();

			for (Field f : fs) {
				String fieldName = f.getName();
				boolean except = f.isAnnotationPresent(DataAnnotationCompareExcept.class);
				
				if (except) {
					continue;
				}
				if ("serialVersionUID".equalsIgnoreCase(fieldName)) {
					continue;
				}
				Method get = getGetMethod(clazz, fieldName);//get the getter method
				
				Object fieldObject1 = get.invoke(o1);
				Object fieldObject2 = get.invoke(o2);
				if(fieldObject1 == null && fieldObject2 == null){
					continue;
				}else if(fieldObject1 != null && fieldObject2 != null){
					if(fieldObject1.equals(fieldObject2)){
						continue;
					}else{
						Log.d(TAG,"fieldName is " + fieldName + " !fieldObject1.equals(fieldObject2) return false");						
						return false;
					}
				}else{
					if(fieldObject1 == null && fieldObject2 != null){
						Log.d(TAG,"fieldName is " + fieldName + " fieldObject1 == null && fieldObject2 != null return false");
					}
					if(fieldObject1 != null && fieldObject2 == null){
						Log.d(TAG,"fieldName is " + fieldName + " fieldObject1 != null && fieldObject2 == null return false");
					}
					return false;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public static Method getGetMethod(Class<?> entity_class, String fieldName) {
		String mn = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
		try {
			return entity_class.getDeclaredMethod(mn);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
     * 对比某个List前后状态是否发生了变化，只适合于T对象内部不发生变化，只是list增加或者减少。如每个T都具有UUid
     *
     * @param ori 第一个list
     * 
     * @param mod 第二个list
     * 
     * @return 返回两个list前后是否不同，返回值中一共包括两个list，
     * 			其中返回的第一个list是删除的元素，第二个list是增加的元素。
     * 			remove函数，会将list中所有的相同的值都剔除掉
     */
	public static <T> List<List<T>> compareList(List<T> ori, List<T> mod){
		ArrayList<T> oriCopy = new ArrayList<T>();
		oriCopy.addAll(ori);
		ori.removeAll(mod);
		mod.removeAll(oriCopy);
		List<List<T>> ret = new ArrayList<List<T>>();
		ret.add(ori);
		ret.add(mod);
		return ret;
	}
	
	
	
}
